# -*- coding: utf-8 -*-

from PyQt5.Qt import *

class RectItem(QGraphicsRectItem):
    '''subclass of QGraphicsRectItem'''
    # public params
    topleft = 1
    topright = 2
    bottomleft = 3
    bottomright = 4


    '''控制有效识别鼠标拖动放缩的识别区域大小'''

    def __init__(self, rect , radius = 20):
        super().__init__()
        self.radius = radius
        self.flag = False  #标志鼠标是否落在可拖放图元大小的区域
        self.label = True #标志鼠标是否正在进行标注，若正在进行标注则暂时取消缩放功能,False表示正在标注，True表示未在标注
        self.setFlags(QGraphicsItem.ItemIsFocusable|QGraphicsItem.ItemIsSelectable)
        self.setFlag(self.ItemIsMovable)
        self.setRect(rect)
        self.area_rc = [] # store rect area of corner
        self.update_data()

    def alter_label(self):
        self.label = not self.label

    def cursor_position(self, pos):
        '''return flag of cursor position'''
        for k, p in self.area_dic.items():
            if p.contains(pos):
                return k
        return None

    def mousePressEvent(self, evt):
        '''rewrite event ,judge whether in areas of rect generated by corner and radius'''
        if evt.buttons() & Qt.LeftButton:
            pos = evt.pos()
            self.pos = self.cursor_position(pos)
            if self.pos:
                self.flag = True

    def mouseMoveEvent(self, evt):
        '''pass parameters and call functions while its condition is satisfied'''
        if self.flag and self.label:
            self.rectResize(evt)
        else:
            if self.label:
                self.setFlag(QGraphicsItem.ItemIsMovable)
            else:
                self.setFlag(QGraphicsItem.ItemIsMovable, False)
            super(RectItem, self).mouseMoveEvent(evt)

    def rectResize(self, mousePos):
        self.prepareGeometryChange()
        update_rect = None
        if self.pos == self.topleft:
            update_rect = standard_rect(mousePos.pos(), self.right_down)
        elif self.pos == self.topright:
            update_rect = standard_rect(mousePos.pos(), self.left_down)
        elif self.pos == self.bottomleft:
            update_rect = standard_rect(mousePos.pos(), self.right_up)
        elif self.pos == self.bottomright:
            update_rect = standard_rect(mousePos.pos(), self.left_up)

        self.setRect(update_rect)

    def mouseReleaseEvent(self, event):
        super(RectItem, self).mouseReleaseEvent(event)
        self.flag = False
        self.update_data()

    def update_data(self):
        '''update data'''
        rect = self.rect()
        corner = [rect.topLeft(), rect.topRight(), rect.bottomLeft(), rect.bottomRight()]  # list: position of corner

        self.area_rc.clear()  # store rect area of corner

        #self.rectPath.clear()
        #self.rectPath.addRect(rect)

        for i in corner:
            self.area_rc.append(rectofcorner(i, self.radius))

        self.area_dic = {self.topleft: self.area_rc[0], self.topright: self.area_rc[1],
                         self.bottomleft: self.area_rc[2], self.bottomright: self.area_rc[3]}

        self.left_up = self.rect().topLeft()
        self.right_up = self.rect().topRight()
        self.left_down = self.rect().bottomLeft()
        self.right_down = self.rect().bottomRight()

        self.x1 = self.rect().x()
        self.y1 = self.rect().y()
        self.x2 = self.right_down.x()
        self.y2 = self.right_down.y()

    def paint(self, painter:QPainter, item, widget=None):
        '''重写绘制事件，主要目的是给绘制的图形增加或改变样式'''
        painter.save()  # 保存画笔的属性，
        painter.setPen(QPen(Qt.red))
        #painter.setBrush(QBrush(Qt.blue))
        #painter.setOpacity(0.5)
        painter.drawRect(self.rect())
        #painter.drawPath(self.rectPath)#画矩形，当然你也可以不使用QPainterPath，而是直接painter.drawRect(self.rect())
        painter.restore()  # 恢复画笔的属性
        if item.state & QStyle.State_Selected or item.state & QStyle.State_HasFocus:
            # 设置 对象被选中为焦点时的 画笔颜色和宽度
            painter.setPen(QPen(Qt.green, 3))
            # 绘制一个边框在矩形上
            painter.drawRect(self.rect())

def rectofcorner(center, radius):
    '''generate rect by point and radius'''
    x = center.x() - radius
    y = center.y() - radius

    return QRectF(x, y, 2 * radius, 2 * radius)

def standard_rect(point1, point2):
    '''Reorganize the given point coordinates so that the starting point is always the smaller abscissa and ordinate,
    and return the rectangle drawn with the adjusted coordinates'''
    rect = None  #An initial value is given to prevent errors with no return value
    x1, y1 = point1.x(), point1.y()
    x2, y2 = point2.x(), point2.y()
    if x1 <= x2 and y1 <= y2:
        rect = QRectF(QPointF(x1, y1), QPointF(x2, y2)).normalized()
    elif x1 > x2 and y1 <= y2:
        rect = QRectF(QPointF(x2, y1), QPointF(x1, y2)).normalized()
    elif x1 <= x2 and y1 > y2:
        rect = QRectF(QPointF(x1, y2), QPointF(x2, y1)).normalized()
    elif x1 > x2 and y1 > y2:
        rect = QRectF(QPointF(x2, y2), QPointF(x1, y1)).normalized()

    return rect

if __name__ == '__main__':
    import sys

    app = QApplication(sys.argv)

    view = QGraphicsView()
    scene = QGraphicsScene()
    scene.setSceneRect(0,0,400,600)
    rect = QRectF(0, 0, 100, 100)
    radius = 20
    scene.addItem(RectItem(rect=rect))
    view.setScene(scene)

    view.show()

    sys.exit(app.exec_())
